#ifndef NEOVIM_QT_TREE
#define NEOVIM_QT_TREE

#include <QList>
#include <QDir>
#include <tuple>
#include "msgpackiodevice.h"
#include "column.h"
#include "neovimconnector.h"

namespace NeovimQt {

class NeovimConnector;

class Tree: public QObject
{
    Q_OBJECT
public:
    Tree();
    ~Tree();
    Tree(int bufnr, int icon_ns_id);
    enum ClipboardMode {COPY, MOVE};
    static ClipboardMode paste_mode;
    static QStringList clipboard;
	static NeovimApi6 *api;
    int bufnr = -1;
    int icon_ns_id = -1;
    Config cfg;
    Context ctx;
    QString input;
    QMap<QString, QVariant> get_candidate(const int);
    void open_tree(const QList<QVariant> &args);
    void open_or_close_tree_recursively(const QList<QVariant> &args);
    void open(const QList<QVariant> &args);
    void cd(const QList<QVariant>& args);
    void toggle_select(const QList<QVariant>& args);
    void toggle_select_all(const QList<QVariant>& args);
    void drop(const QList<QVariant>& args);
    void print(const QList<QVariant>& args);
    void pre_paste(const QList<QVariant>& args);
    void paste(const int ln, const QString &src, const QString &dest);
    void pre_remove(const QList<QVariant> &args);
    void remove();
    void yank_path(const QList<QVariant>& args);
    void call(const QList<QVariant>& args);
    void copy(const QList<QVariant>& args);
    void move(const QList<QVariant>& args);
    void debug(const QList<QVariant>& args);
    void toggle_ignored_files(const QList<QVariant>& args);
    void redraw(const QList<QVariant>& args);
    void new_file(const QList<QVariant>& args);
    void execute_system(const QList<QVariant>& args);
    void rename(const QList<QVariant>& args);
    void action(const QString &action, const QList<QVariant> &args, const QMap<QString, QVariant> context);
    void goto_(const QList<QVariant> &args);

    void changeRoot(QString path);
    void redraw_line(int sl, int el);
    void redraw_recursively(int l);
    void _copy_or_move(const QList<QVariant>& args);
    void vim_input(string prompt, string text, string completion, string handle);
    inline void buf_set_lines(int s, int e, bool strict, QList<QByteArray> replacement)
    {
        api->nvim_buf_set_option(bufnr, "modifiable", true);
        api->nvim_buf_set_lines(bufnr, s, e, strict, replacement);
        api->nvim_buf_set_option(bufnr, "modifiable", false);
        // TODO: Fine-grained targets update
        collect_targets();
    };
    inline void set_dir(QDir &dir)
    {
        // TODO: QDir::setNameFilters
        QDir::Filters filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot;
        if (cfg.show_ignored_files)
            filters |= QDir::Hidden;
        dir.setFilter(filters);
        dir.setSorting(QDir::Name|QDir::DirsFirst);
// QDir::Name     Sort by name.
// QDir::Time     Sort by time (modification time).
// QDir::Size     Sort by file size.
// QDir::Type     Sort by file type (extension).
// QDir::Unsorted 	 Do not sort.
// QDir::NoSort     Not sorted by default.
// QDir::DirsFirst	 Put the directories first, then the files.
// QDir::DirsLast	 Put the files first, then the directories.
// QDir::Reversed	 Reverse the sort order.
// QDir::IgnoreCase Sort case-insensitively.
// QDir::LocaleAware  Sort items appropriately using the current locale settings.
    };


protected slots:
    void handleRename(const QVariant& val);
    void handleNewFile(const QVariant& val);

private:

    QList<FileItem *> m_fileitem;
    QHash<int, QList<Cell>> col_map;
    QHash<QString, bool> expandStore;
    QHash<QString, int> cursorHistory;
    QList<int> targets;
    void hline(int sl, int el);
    int find_parent(int l);
    std::tuple<int, int> find_range(int l);
    void insert_entrylist(const QList<FileItem*> &, const int pos, QList<QByteArray>& ret);
    void insert_item(const int pos);
    void collect_targets();
    void save_cursor();
    void insert_rootcell(const int pos);
    void erase_entrylist(const int s, const int e);
    void makeline(const int pos, QByteArray &line);
    void entryInfoListRecursively(const FileItem &, QList<FileItem*>& fileitem_lst);
    void _toggle_select(const int pos);

    void shrinkRecursively(const QString &path);
    void expandRecursively(const FileItem&, QList<FileItem*> &fileitem_lst);
};

} // namespace NeovimQt

#endif
